package main

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/dadjin/my-commonly-used-go-func/MyTool/FileTool"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

type ToGoDirInfo struct {
	OutPackageName string `json:"OutPackageName"`
	ArrVarName     string `json:"ArrVarName"`
	FromDir        string `json:"FromDir"`
	ToPath         string `json:"ToPath"`
}

type ToGoDirConfig struct {
	ToGoDir []ToGoDirInfo `json:"ToGoDir"`
}

func main() {
	var config ToGoDirConfig
	jsonData := FileTool.ReadWholeFile("config.json")
	err := json.Unmarshal([]byte(jsonData), &config)
	if err != nil {
		fmt.Println("Error parsing JSON:", err)
		return
	}

	for _, configObj := range config.ToGoDir {
		var allFilePath []string
		if !FileTool.IsDir(configObj.FromDir) {
			fmt.Println(configObj.FromDir + " is not dir")
			continue
		}

		filepath.Walk(configObj.FromDir, func(path string, info os.FileInfo, err error) error {
			if FileTool.IsFile(path) {
				allFilePath = append(allFilePath, path)
			}

			return nil
		})

		fmt.Println("all path to map")
		objbool, err := outFileToGo(configObj, allFilePath)
		if objbool {
			fmt.Println(configObj.ToPath + " is ok")
		} else {
			fmt.Println(configObj.ToPath+" err:", err)
		}

	}
}

func outFileToGo(configObj ToGoDirInfo, allFilePath []string) (bool, error) {
	// outPath string（configObj.ToPath）, OutPackageName string（configObj.OutPackageName）, ArrVarName string(configObj.ArrVarName)
	hasPath, err := FileTool.PathExists(configObj.ToPath)
	if err != nil {
		return false, err
	}
	//判断outPath 是否存在

	if hasPath {
		return false, errors.New("outPath has file,you must delect outPath file")
	}
	//写入头部
	FileTool.AppendToFile(configObj.ToPath, startGoCode(configObj))
	allFilePathNum := len(allFilePath)
	nowFilePut := 0
	//写入内容
	for _, filePath := range allFilePath {
		fileByte, err := os.ReadFile(filePath)
		if err != nil {
			fmt.Println(filePath+" Error reading file:", err)
			time.Sleep(time.Second * 2)
			continue
		}
		nowFilePut++
		fmt.Println("now out(" + strconv.Itoa(nowFilePut) + "/" + strconv.Itoa(allFilePathNum) + "):" + filePath)
		FileTool.AppendToFile(configObj.ToPath, "\tmymapfile[\""+base64.StdEncoding.EncodeToString([]byte(filePath))+"\"] = []byte(")
		FileTool.AppendToFile(configObj.ToPath, fmt.Sprintf("%q", fileByte))
		FileTool.AppendToFile(configObj.ToPath, ")\n")

	}
	//写入尾部
	FileTool.AppendToFile(configObj.ToPath, endGoCode(configObj))
	return true, nil
}

func startGoCode(configObj ToGoDirInfo) string {
	startGoCodeString := `
package main

import (
	"encoding/base64"
	"errors"
	"sync"
)

var TestVar = make(map[string][]byte)
var cacheKeyTestVar = make(map[string]bool)
var muTestVar sync.RWMutex
var isGlobalTestVar = false
var isInitTestVar = false

// 设置是否为全局变量
func SetTestVarIsGlobal(ArrVarIsGlobal bool) {
	muTestVar.Lock()
	defer muTestVar.Unlock()
	//判断如果启动全局，并且没有key 并且Init初始化过 则重新载入
	if ArrVarIsGlobal && len(cacheKeyTestVar) <= 0 && isInitTestVar {
		for stringKey, byteValue := range GetALLTestVar() {
			cacheKeyTestVar[stringKey] = true
			if isGlobalTestVar {
				TestVar[stringKey] = byteValue
			}
		}
	} else {
		if len(cacheKeyTestVar) > 0 {
			cacheKeyTestVar = nil
			TestVar = nil
		}
	}
	isGlobalTestVar = ArrVarIsGlobal
}

// 初始化
func InitTestVar() (bool, error) {
	muTestVar.Lock()
	defer muTestVar.Unlock()
	if isInitTestVar == true {
		return false, errors.New("You have already used this function")
	}
	isInitTestVar = true
	for stringKey, byteValue := range GetALLTestVar() {
		cacheKeyTestVar[stringKey] = true
		if isGlobalTestVar {
			TestVar[stringKey] = byteValue
		}
	}
	return true, nil
}

// 根据key获取变量
func GetTestVar(key string) ([]byte, error) {
	key = base64.StdEncoding.EncodeToString([]byte(key))
	muTestVar.RLock()
	defer muTestVar.RUnlock()
	//判断是否启动Init
	if !isInitTestVar {
		return nil, errors.New("You must use InitTestVar function")
	}
	//判断key是否在cacheKey内
	if !cacheKeyTestVar[key] {
		return nil, errors.New("Key not found")
	}
	//是全局且有key
	if isGlobalTestVar && len(cacheKeyTestVar) > 0 {
		return TestVar[key], nil
	}
	return GetALLTestVar()[key], nil
}

// 获取所有key信息
func GetAllKeyTestVar() (map[string]string, error) {
	muTestVar.RLock()
	defer muTestVar.RUnlock()
	//判断是否启动Init
	if !isInitTestVar {
		return nil, errors.New("You must use InitTestVar function")
	}
	keyAndBased64 := make(map[string]string)
	for stringKey, _ := range cacheKeyTestVar {
		decodeVale, err := base64.StdEncoding.DecodeString(stringKey)
		if err != nil {
			continue
		}
		keyAndBased64[stringKey] = string(decodeVale)
	}
	return keyAndBased64, nil
}
func GetALLTestVar() map[string][]byte {
	var mymapfile = make(map[string][]byte)

`
	//把上面字符串的包和变量替换成自定义
	startGoCodeString = strings.ReplaceAll(startGoCodeString, "package main", "package "+configObj.OutPackageName)
	startGoCodeString = strings.ReplaceAll(startGoCodeString, "TestVar", configObj.ArrVarName)
	return startGoCodeString
}

func endGoCode(configObj ToGoDirInfo) string {
	endGoCodeString := `
	return mymapfile
}

`
	return endGoCodeString

}
